﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using EmgrMvc.Models;
using EmgrMvc.BLL;
using Quartz;

namespace EmgrMvc.Controllers
{
    public class DevicesController : Controller
    {
        private readonly MyContext _context;
        MqttTool tool;

        public DevicesController(MyContext context)
        {
            _context = context;
            tool = MqttTool.getSingleton(); // new MqttTool();
        }

        void IRControl(int devId, string action)
        {
            var dev = _context.Devices.Find(devId);
            var devt = _context.Types.Find(dev.Type);
            string topic;
            string filename = "Data/";
            if (action == "ON")
            {
                topic = "action/on/" + dev.ControllerNode + dev.Topic;
                filename += devt.DataFileOn;
            }
            else
            {
                topic = "action/on/" + dev.ControllerNode + dev.Topic;
                filename += devt.DataFileOff;
            }

            tool.ACControl(topic, filename);
        }

        // GET: Devices
        public async Task<IActionResult> Index()
        {
            return View(await _context.Devices.ToListAsync());
        }

        // GET: Devices/Details/5
        public async Task<IActionResult> Details(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var device = await _context.Devices
                .FirstOrDefaultAsync(m => m.Id == id);
            if (device == null)
            {
                return NotFound("设备找不到");
            }

            var type = await _context.Types.FirstOrDefaultAsync(t => t.Id == device.Type);
            if (type == null)
            {
                return NotFound("设备类型找不到");
            }

            ViewBag.Catalog = type.Catalog;

            return View(device);
        }

        // GET: Devices/Create
        public IActionResult Create()
        {
            ViewBag.Types = new SelectList(_context.Types.ToList(), "Id", "Name");
            ViewBag.Controllers = new SelectList(_context.MqttControllers.ToList(), "Path", "Name");
            return View();
        }

        // GET: Devices/Create
        public IActionResult CreateWOLDevice()
        {
            ViewBag.Controllers = new SelectList(_context.MqttControllers.ToList(), "Path", "Name");
            return View("CreateWOLDevice");
        }


        // POST: Devices/Create
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Create([Bind("Id,Name,Description,Type,ControllerNode,Topic,Data")] Device device)
        {
            if (ModelState.IsValid)
            {
                if (device.Type == "wol")
                {
                    device.Topic = "/wol/" + device.Data.Replace(":", "").ToLower();
                }

                _context.Add(device);
                await _context.SaveChangesAsync();
                return RedirectToAction(nameof(Index));
            }
            return View(device);
        }

        public IActionResult AddIRDevice()
        {
            ViewBag.Controllers = new SelectList(_context.MqttControllers.ToList(), "Name", "Name");
            ViewBag.DeviceTypes = new SelectList(_context.Types.Where(t => t.Catalog == "IR").ToList(), "Id", "Name");
            return View();
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> AddIRDevice([Bind("Id,Name,Description,Type,ControllerNode,Topic,Data")] Device device)
        {
            if (ModelState.IsValid)
            {
                _context.Add(device);
                await _context.SaveChangesAsync();
                return RedirectToAction(nameof(Index));
            }
            return View(device);
        }

        public IActionResult AddIRJob()
        {
            ViewBag.Devices = _context.Devices.ToList();
            return View();
        }

        [HttpPost]
        public IActionResult AddIRJob(int[] devs, string Action, int DelayMinutes)
        {
            List<Device> Devices = new List<Device>();
            //Devices.Add(_context.Devices.Find(5));
            foreach(int dev in devs)
            {
                Devices.Add(_context.Devices.Find(dev));
            }

            //创建作业和触发器
            var jobDetail = JobBuilder.Create<IRControlJob>()
                .WithIdentity("id1", "group1")
                .SetJobData(new JobDataMap() {
                                new KeyValuePair<string, object>("Action", Action),
                                new KeyValuePair<string, object>("Devices", Devices),
                                new KeyValuePair<string, object>("Types", _context.Types.ToList()),
                                new KeyValuePair<string, object>("DbContext", _context)
                            }).Build();
            var trigger = TriggerBuilder.Create()
                                        //.WithCronSchedule("0 3 6 * * ?")
                                        //.WithSimpleSchedule(m => m.WithRepeatCount(3).WithIntervalInMinutes(1))
                                        .StartAt(DateTime.Now + TimeSpan.FromMinutes(DelayMinutes))
                                        .Build();

            //添加调度
            IScheduler scheduler = ScheduleTool.scheduler;
            scheduler.ScheduleJob(jobDetail, trigger);

            ViewBag.Devices = _context.Devices.ToList();
            return View();
        }

        // GET: Devices/Edit/5
        public async Task<IActionResult> Edit(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var device = await _context.Devices.FindAsync(id);
            if (device == null)
            {
                return NotFound();
            }
            return View(device);
        }

        // POST: Devices/Edit/5
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Edit(int id, [Bind("Id,Name,Description,Type,ControllerNode,Topic,Data")] Device device)
        {
            if (id != device.Id)
            {
                return NotFound();
            }

            if (ModelState.IsValid)
            {
                try
                {
                    _context.Update(device);
                    await _context.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (!DeviceExists(device.Id))
                    {
                        return NotFound();
                    }
                    else
                    {
                        throw;
                    }
                }
                return RedirectToAction(nameof(Index));
            }
            return View(device);
        }

        // GET: Devices/Delete/5
        public async Task<IActionResult> Delete(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var device = await _context.Devices
                .FirstOrDefaultAsync(m => m.Id == id);
            if (device == null)
            {
                return NotFound();
            }

            return View(device);
        }

        // GET: Devices/Delete/5
        public async Task<IActionResult> WakeupPC(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var device = await _context.Devices
                .FirstOrDefaultAsync(m => m.Id == id);
            if (device == null)
            {
                return NotFound();
            }

            tool.WakeupPC("action/on/" + device.ControllerNode + "/wol", device.Data);
            return RedirectToAction("Details", new { id = id });
        }

        public IActionResult ACPowerOn(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            IRControl(id.Value, "ON");
            return RedirectToAction("Details", new { id = id });
        }

        public IActionResult ACPowerOff(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            IRControl(id.Value, "OFF");
            return RedirectToAction("Details", new { id = id });
        }

        public IActionResult PowerOn(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            EsysBLL esysBLL = new EsysBLL(_context);
            esysBLL.PowerOnDevice(id.Value);

            return RedirectToAction("Details", new { id = id });
        }

        public IActionResult PowerOff(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            EsysBLL esysBLL = new EsysBLL(_context);
            esysBLL.PowerOffDevice(id.Value);

            return RedirectToAction("Details", new { id = id });
        }

        public IActionResult Batch()
        {
            var devices = from d in _context.Devices join t in _context.Types on d.Type equals t.Id
                          where t.Catalog == "IR"
                          select d;
            ViewBag.listItems = new SelectList(devices.ToList(), "Id", "Name");
            return View();
        }

        [HttpPost]
        public IActionResult Batch(string[] devices)
        {
            foreach(var dev in devices)
            {
                IRControl(int.Parse(dev), "OFF");
            }
            return Redirect("Batch");
        }

        // POST: Devices/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> DeleteConfirmed(int id)
        {
            var device = await _context.Devices.FindAsync(id);
            _context.Devices.Remove(device);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }

        private bool DeviceExists(int id)
        {
            return _context.Devices.Any(e => e.Id == id);
        }
    }
}
